// 定义Worker内部使用的类型
interface ChunkContext {
  index: number;
  totalChunks: number;
  fileName: string;
  chunk: ArrayBuffer;
}

const MAX_RETRY = 3;
const CHUNK_HEADER_SIZE = 16;

self.onmessage = async (e: MessageEvent<ChunkContext>) => {
  try {
    const result = await processChunk(e.data);
    self.postMessage({
      type: "chunk-success",
      index: result.index,
      hash: result.hash,
    });
  } catch (error) {
    self.postMessage({
      type: "chunk-error",
      index: e.data.index,
      error: error instanceof Error ? error : new Error("Unknown error"),
    });
  }
};

async function processChunk(
  context: ChunkContext
): Promise<{ index: number; hash: string }> {
  // 1. 计算分片哈希
  const hash = await calculateHash(context.chunk);

  // 2. 构建分片头信息
  const header = createHeader(context, hash);

  // 3. 组合分片数据
  const payload = combineHeaderAndChunk(header, context.chunk);

  // 4. 模拟网络请求（实际应替换为真实API调用）
  await simulateNetworkRequest(payload, context.index);

  return { index: context.index, hash };
}

function createHeader(context: ChunkContext, hash: string): ArrayBuffer {
  const header = new ArrayBuffer(CHUNK_HEADER_SIZE);
  const view = new DataView(header);

  // 使用小端序存储
  view.setUint32(0, context.index, true);
  view.setUint32(4, context.totalChunks, true);
  view.setUint32(8, hash.length, true);
  view.setUint32(12, context.chunk.byteLength, true);

  return header;
}

function combineHeaderAndChunk(
  header: ArrayBuffer,
  chunk: ArrayBuffer
): ArrayBuffer {
  const result = new Uint8Array(header.byteLength + chunk.byteLength);
  result.set(new Uint8Array(header), 0);
  result.set(new Uint8Array(chunk), header.byteLength);
  return result.buffer;
}

async function calculateHash(buffer: ArrayBuffer): Promise<string> {
  const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
  return Array.from(new Uint8Array(hashBuffer))
    .map((b) => b.toString(16).padStart(2, "0"))
    .join("");
}

async function simulateNetworkRequest(
  data: ArrayBuffer,
  attempt: number
): Promise<void> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() < 0.2 && attempt < 3) {
        // 模拟20%失败率
        reject(new Error(`Network error (attempt ${attempt + 1})`));
      } else {
        resolve();
      }
    }, 1000);
  });
}
